import moize from "moize";
/** x, y, distance */
export type PositionArray = [number, number, number];
/** 距离函数，使用率较高 */
const distance = moize(function (x: number, y: number, ratio: number) {
    return Math.sqrt(Math.pow(y * ratio, 2) + Math.pow(x, 2));
});

/** 判断是否为圆的函数 */
const isInCircle = function (
    x: number,
    y: number,
    radius: number,
    ratio: number
) {
    return distance(x, y, ratio) <= radius;
};

const fatFilled = function (
    x: number,
    y: number,
    radius: number,
    ratio: number
) {
    const around = [
        [x + 1, y],
        [x + 1, y + 1],
        [x + 1, y - 1],
        [x - 1, y],
        [x - 1, y + 1],
        [x - 1, y - 1],
        [x, y + 1],
        [x, y - 1],
    ];
    return (
        isInCircle(x, y, radius, ratio) &&
        !around.every(([x, y]) => isInCircle(x, y, radius, ratio))
    );
};

/** 绘制一个像素圆
 * @param circleType edge 为圆的边界，fulfilled 为圆
 */
export function drawCircle(
    width_r: number,
    height_r: number,
    circleType: "edge" | "fulfilled" = "fulfilled"
) {
    const ratio = width_r / height_r;
    let iFilled = 0;
    let maxBlocks_x, maxBlocks_y;
    // 判断是否为小数
    maxBlocks_x =
        (width_r * 2) % 2 == 0
            ? Math.ceil(width_r - 0.5) * 2 + 1
            : Math.ceil(width_r) * 2;
    maxBlocks_y =
        (height_r * 2) % 2 == 0
            ? Math.ceil(height_r - 0.5) * 2 + 1
            : Math.ceil(height_r) * 2;

    const result: PositionArray[] = [];
    for (let y = -maxBlocks_y / 2 + 1; y <= maxBlocks_y / 2 - 1; y++) {
        for (let x = -maxBlocks_x / 2 + 1; x <= maxBlocks_x / 2 - 1; x++) {
            let xFilled = false;
            switch (circleType) {
                case "edge":
                    xFilled = fatFilled(x, y, width_r, ratio);
                    break;
                case "fulfilled":
                    xFilled = isInCircle(x, y, width_r, ratio);
                    break;
            }
            if (xFilled) {
                iFilled += 1;
                // 被缓存过，所以可以直接调用
                const rDistance = distance(x, y, ratio);
                result.push([x - 0.5, y - 0.5, rDistance / width_r]);
            }
        }
    }
    return result;
}
